import {equalsTo} from "../core/Obj";
import IllegalArgumentException from "../exceptions/IllegalArgumentException";
import List from "../list/List";
import ArrayList from "../list/ArrayList";

/**
 * 一些静态的，针对{@link Array}的方法。
 *
 * @version 1.0
 */
export default class Arrays {
  /**
   * 通过依次对两个数组进行比较，判断这两个数组是否相等。
   *
   * 如果两个数组长度相等，则进行依次比较。否则直接判定为不相等。
   *
   * @param a 第一个数组
   * @param b 第二个数组
   * @return {boolean} 两个数组是否相等
   * @version 1.0
   */
  public static equals<E>(a: E[], b: E[]): boolean {
    if (a === b) {
      return true;
    } else if (a.length !== b.length) {
      return false;
    } else {
      let flag = true;
      for (let i = 0; i < a.length; i++) {
        if (!equalsTo(a[i], b[i])) {
          flag = false;
          break;
        }
      }
      return flag;
    }
  }

  /**
   * 使用指定的元素，填满一个全新的数组。
   *
   * @param e 需要填充到数组中的元素
   * @param length 需要填充的数组的长度
   * @return {E[]} 填充完毕的数组
   * @throws {IllegalArgumentException} 填充的长度小于或等于0
   * @version 1.0
   */
  public static fill<E>(e: E, length: number): E[] {

    if (length <= 0) {
      throw new IllegalArgumentException("length " + length + " should be bigger than 0");
    }

    const array: E[] = [];
    array.fill(e, 0, length);
    return array;
  }

  /**
   * 使用一个迭代器来填满一个全新的数组。
   *
   * @param iterator 含有需要填入的元素的迭代器
   * @see Iterator
   * @return {E[]} 填充完毕的数组
   * @version 1.0
   */
  public static fillByIterator<E>(iterator: Iterator<E>): E[] {
    const array: E[] = [];
    let element;
    do {
      element = iterator.next();
      array.push(element.value);
    } while (element.done);
    return array;
  }

  /**
   * 从指定的数组中，根据起始索引和结束索引进行数据的浅拷贝并收集到一个新的数组中。
   *
   * 当结束值小于初始值时，系统会将这两个值进行交换，以满足正常的浅复制。
   *
   * 索引必须位于0-数组长度中，当超出范围则会抛出异常。
   *
   * @param original 原始数组
   * @param from 需要复制的起始索引
   * @param to 需要复制的结束索引
   * @return {E[]} 拷贝完成的数组
   * @throws {IllegalArgumentException} 起始索引或结束索引不符合要求
   * @version 1.0
   */
  public static copyOf<E>(original: E[], from?: number, to?: number): E[] {
    if (from === undefined) {
      from = 0;
    } else if (from < 0 || from > original.length) {
      throw new IllegalArgumentException("from value " + from + " should between 0 and the length of original " + original.length);
    }
    if (to === undefined) {
      to = original.length;
    } else if (to < 0 || to > original.length) {
      throw new IllegalArgumentException("to value " + to + " should between 0 and the length of original " + original.length);
    }

    if (from >= to) {
      let temp = to;
      to = from;
      from = temp;
    }

    return original.slice(from, to);
  }

  public static asList<E>(...values: E[]): List<E> {
    return new ArrayList(values, -1);
  }
}
